;; https://projecteuler.net/problem=7

;; Find n-th prime number

;; Problem 7

;; By listing the first six prime numbers: 2, 3, 5, 7, 11,
;; and 13, we can see that the 6th prime is 13.

;; What is the 10 001st prime number?


(import
  (except (rnrs base) let-values)
  (only (guile) lambda* λ))


(define calc-check-limit
  (λ (n)
    "Calculate the number up to which one needs to check for
factors."
    (inexact->exact (floor (sqrt n)))))


(define too-high?
  (λ (num limit)
    "Check, whether the number is above the limit."
    (> num limit)))


(define prime?
  (λ (num)
    "Check, whether the given number NUM is a prime number."
    (let ([limit (calc-check-limit num)])
      (let loop ([test-num 2])
        (cond
         [(too-high? test-num limit) #t]
         [else
          (cond
           [(= (remainder num test-num) 0) #f]
           [else
            (loop (+ test-num 1))])])))))


(define next-num
  (λ (num)
    "Even numbers, except for 2, cannot be primes, so we add
2, to skip even numbers between odd numbers. This function
assumes, that one gives it odd numbers as input."
    (+ num 2)))


(define n-th-prime
  (λ (n)
    "Find the n-th prime number and return it."
    ;; Iterate through the numbers from 3 towards infinity,
    ;; until the n-th prime has been found.
    (let loop ([current-num 3] [found-primes 1])
      (let ([is-prime (prime? current-num)])
        (cond
         [(= found-primes (- n 1))
          (if is-prime
              current-num
              (loop (next-num current-num) found-primes))]
         [else
          (if is-prime
              (loop (next-num current-num) (+ found-primes 1))
              (loop (next-num current-num) found-primes))])))))


(simple-format
 (current-output-port)
 "~a\n"
 (n-th-prime 10001))  ; 104743
